package com.example.meeting.controller;

import com.example.meeting.model.domain.Admin;
import com.example.meeting.model.responseData.CommonResult;
import com.example.meeting.shiro.JwtToken;
import com.example.meeting.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RestController
public class LoginController {
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private RedisSessionDAO redisSessionDAO;

    /**
     * 管理员登录接口
     * @param response
     * @param admin
     * @return
     */
    @PostMapping(value = "/admin/login")
    public CommonResult AdminLogin(HttpServletResponse response,@Validated @RequestBody Admin admin) {
        String token= jwtUtils.generateToken(admin.getUsername());
        Subject subject = SecurityUtils.getSubject();
        try{
            subject.login(new JwtToken(token));
        }catch(Exception e){
            return CommonResult.fail(e.getMessage());
        }
        //Map集合封装返回数据
        Map<String, Object> map = new ConcurrentHashMap<>();
        if(subject.isAuthenticated()){
            //获取Admin对象
            Admin principal = (Admin) subject.getPrincipal();
            if(!passwordEncoder.matches(admin.getPassword(),principal.getPassword())){
                //如果密码不匹配
                return CommonResult.fail("登录失败，密码输入有误");
            }
            //将获取到的Admin对象添加到返回数据map中
            map.put("admin",principal);
        }else{
            return CommonResult.fail("登录失败");
        }
        //设置响应体
        response.setHeader("Authorization", token);
        response.setHeader("Access-control-Expose-Headers", "Authorization");
        //获取当前会话
        Session session = SecurityUtils.getSubject().getSession();
        //获取sessionId
        Serializable sessionId = session.getId();
        //添加token到返回数据map中
        map.put("token", token);
        //将当前登录用户的用户名添加到session中
        session.setAttribute("username",admin.getUsername());
        //将当前登录用户的用户名和sessionId添加到redis中
        RedisUtil.set(admin.getUsername(),sessionId,session.getTimeout());
        //重置redis中会话管理的过期时间
        redisSessionDAO.setExpire(7200);
        //把当前token存入redis管理
        RedisUtil.set(admin.getUsername()+"_token",token,session.getTimeout());
        log.info("用户名：{} 登录成功",admin.getUsername());
        return CommonResult.success("登录成功", map);
    }

    /**
     * 管理员登出接口
     * @return
     */
    @GetMapping(value = "/admin/logout")
    public CommonResult adminLogout(){
        Subject subject = SecurityUtils.getSubject();
        //获取当前会话
        Session session = subject.getSession();
        //判断当前会话是否已经失效
        if (session.getAttribute("username") != null){
            //删除自定义的当前用户会话信息
            RedisUtil.remove((String) session.getAttribute("username"));
            //删除自定义的当前用户token信息
            if (RedisUtil.hasKey((String) session.getAttribute("username")+"_token")){
                //删除自定义的当前用户token信息
                RedisUtil.remove((String) session.getAttribute("username")+"_token");
            }
        }
        //获取Admin对象
        Admin admin = (Admin) subject.getPrincipal();
        //调用退出登录
        subject.logout();
        log.info("用户名：{} 登出成功",admin.getUsername());
        return CommonResult.success("登出成功");
    }

    //对未登录访问做处理
    @GetMapping(value = "/auth/401")
    public CommonResult unLogin(){
        return CommonResult.fail("您还未登录，请先登录");
    }

    //对无权限访问做处理
    @GetMapping(value = "/auth/403")
    public CommonResult unPermission(){
        return CommonResult.fail("您没有权限访问该接口");
    }
}
